package main

import (
	"fmt"
	"unsafe"
)

/**
golang的三种指针类型
具体类型的指针，如*int、*string等
unsafe.Pointer，在unsafe下面，任何具体类型的指针都能转化成Pointer，可以实现不同类型的指针的互相转化，充当桥梁的作用
uintptr，golang源码的注释为能存储任何类型的指针的类型，uintptr可以进行指针计算，然后对对应的指针地址的变量进行复制，完成一些黑魔法
*/
type MyPointer struct {
}

type Demo struct {
	a int32
	b byte
	c int64
}

/**
unsafe.Pointer 官方文档对该类型有四个重要描述
//	1- A pointer value of any type can be converted to a Pointer.	任何类型的指针都可以被转化为Pointer
//	2- A Pointer can be converted to a pointer value of any type.	Pointer可以被转化为任何类型的指针
//	3- A uintptr can be converted to a Pointer.		uintptr可以被转化为Pointer
//	4- A Pointer can be converted to a uintptr.		Pointer可以被转化为uintptr
*/
func (m *MyPointer) convert() {
	var a int = 9
	fmt.Println(fmt.Sprintf("a的指针:%v,%T", &a, &a))
	var aPointer = unsafe.Pointer(&a)
	fmt.Println(fmt.Sprintf("1- a的指针->Pointer:%v,%T", aPointer, aPointer))
	var aType = (*int)(aPointer)
	fmt.Println(fmt.Sprintf("2- a的指针的Pointer -> a指针:%v,%T", aType, aType))
	var aUintPtr = uintptr(aPointer)
	fmt.Println(fmt.Sprintf("4- a的指针的Pointer -> uintptr:%v,%T", aUintPtr, aUintPtr))
	var aPointer2 = unsafe.Pointer(aUintPtr)
	fmt.Println(fmt.Sprintf("3- a的指针的uintptr -> Pointer:%v,%T", aPointer2, aPointer2))
}

func (m *MyPointer) usage() {
	d := new(Demo)
	// 获取a的地址并转化为int32，然后进行赋值
	*(*int32)(unsafe.Pointer(d)) = 1
	// 获取b的地址，需要加上int32的地址，然后进行赋值
	*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(d)) + unsafe.Sizeof(int32(0)))) = 'a'
	// 获取c的地址，需要加上int64的大小，因为进行了内存对齐，int32加上byte为5byte，比int64的8byte小，就只需要一个int64就行
	*(*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(d)) + unsafe.Sizeof(int64(0)))) = 2

	fmt.Println(d)
	// 使用偏移量来找到b
	*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(d)) + unsafe.Offsetof(d.b))) = 'b'
	*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(d)) + unsafe.Offsetof(d.c))) = 3
	fmt.Println(d)
}

var x struct {
	a float64
	b bool
	c float64
	// string alignment=8, size=16 内部包含一个指向数据的指针（8个字节）和一个 int 的长度（8个字节） 所以alignment是字段最长的那个，都是8
	d string
	e []int // slice alignment=8, size=24 内部包含一个指向数据的指针（8个字节）和一个 int 的长度（8个字节）和一个 int 的容量（8个字节）
}

func main() {
	p := new(MyPointer)
	p.convert()
	p.usage()

	/**
	x Size:64, Alignment:8
	x.a Size:8, Alignment:8, Offset:0
	x.b Size:1, Alignment:1, Offset:8
	x.c Size:8, Alignment:8, Offset:16
	x.d Size:16, Alignment:8, Offset:24
	x.e Size:24, Alignment:8, Offset:40
	*/
	fmt.Printf("x Size:%d, Alignment:%d\n", unsafe.Sizeof(x), unsafe.Alignof(x))
	fmt.Printf("x.a Size:%d, Alignment:%d, Offset:%d \n", unsafe.Sizeof(x.a), unsafe.Alignof(x.a), unsafe.Offsetof(x.a))
	fmt.Printf("x.b Size:%d, Alignment:%d, Offset:%d \n", unsafe.Sizeof(x.b), unsafe.Alignof(x.b), unsafe.Offsetof(x.b))
	fmt.Printf("x.c Size:%d, Alignment:%d, Offset:%d \n", unsafe.Sizeof(x.c), unsafe.Alignof(x.c), unsafe.Offsetof(x.c))
	fmt.Printf("x.d Size:%d, Alignment:%d, Offset:%d \n", unsafe.Sizeof(x.d), unsafe.Alignof(x.d), unsafe.Offsetof(x.d))
	fmt.Printf("x.e Size:%d, Alignment:%d, Offset:%d \n", unsafe.Sizeof(x.e), unsafe.Alignof(x.e), unsafe.Offsetof(x.e))
	fmt.Println("|aaaa|aaaa|b---|----|cccc|cccc|dddd|dddd|dddd|dddd｜eeee|eeee|eeee|eeee|eeee|eeee|")
}
